package view.rooms
{
	import events.library.EventRemoveLibraryItems;
	import events.room.EventAddItemToRoom;
	import events.room.EventCreateNewRoom;
	import events.room.EventCurrentPerspectiveChange;
	import events.room.EventObjectsPropertyChanged;
	import events.room.EventRemoveRoomItems;
	import events.room.EventRemoveRooms;
	import events.room.EventSetObjectsProperty;
	import events.room.EventSetRoomProperty;
	import events.room.EventSetSelection;
	import events.room.EventSetTilesProperty;
	import events.room.EventTilesPropertyChanged;
	
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.setTimeout;
	
	import model.ModelLibrary;
	import model.ModelRooms;
	import model.ModelSelection;
	
	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	import mx.core.UIComponent;
	import mx.events.CloseEvent;
	import mx.events.CollectionEvent;
	import mx.events.DragEvent;
	import mx.events.FlexEvent;
	import mx.managers.DragManager;
	
	import org.flashIso.engine.base.IsoMap;
	import org.flashIso.engine.base.IsoPerspective;
	import org.flashIso.engine.base.IsoRoom;
	import org.flashIso.engine.core.IsoObjectBase;
	import org.flashIso.engine.core.Point2D;
	import org.flashIso.engine.core.Point3D;
	import org.flashIso.engine.core.ValidateQue;
	import org.flashIso.engine.library.objects.LBase;
	import org.flashIso.engine.objects.IsoImage;
	import org.flashIso.engine.objects.IsoObject;
	import org.flashIso.engine.objects.IsoTile;
	import org.robotlegs.mvcs.Mediator;
	
	import others.Util;
	
	import spark.events.IndexChangeEvent;
	
	public class MediatorScreenRooms extends Mediator
	{
		[Inject]
		public var v:ScreenRooms;
		
		[Inject]
		public var mr:ModelRooms;
		
		[Inject]
		public var ms:ModelSelection;
		
		[Inject]
		public var ml:ModelLibrary;
		
		private var roomControls:Array;
		private var tilesControls:Array;
		private var objectsControls:Array;
		private var otherControls:Array;
		
		private var dragPosition:Point2D;
		private var objectMoved:Boolean = false;
		private var startDragObject:IsoObject;
		
		private var currentRoom:IsoRoom;
		
		override public function onRegister() : void  {
			roomControls = [v.perspectiveXAngle, v.perspectiveYAngle, v.perspectiveZAngle, v.cellXSize, v.cellYSize, v.gridSize, 
				v.background, v.backgroundAlpha, v.backgroundOffsetX, v.backgroundOffsetY, v.backgroundRotation,
				v.backgroundRotation, v.backgroundScaleX, v.backgroundScaleY, v.backgroundFrame, v.foreground, v.foregroundAlpha, v.foregroundOffsetX,
				v.foregroundOffsetY, v.foregroundRotation, v.foregroundRotation, v.foregroundScaleX, v.foregroundScaleY, v.foregroundFrame ];
			tilesControls = [v.tileWalkable, v.tileCustomProperty, v.tileName, v.tileImageFrame, v.tileAlpha];
			objectsControls = [v.objectAlpha, v.objectRotation, v.objectX, v.objectY, v.objectZ, v.objectCustomProperty, v.objectName, v.objectImageFrame];
			otherControls = [v.showAxis, v.showGrid, v.hideBackground, v.hideForeground, v.hideTiles, v.hideObjects, v.showObjectsHeight];
			
			var i:uint;
			for (i = 0; i < roomControls.length; i++){
				eventMap.mapListener(roomControls[i], Event.CHANGE, roomControlChange);
				eventMap.mapListener(roomControls[i], FlexEvent.VALUE_COMMIT, roomControlChange);
			}
			for (i = 0; i < tilesControls.length; i++){
				eventMap.mapListener(tilesControls[i], Event.CHANGE, tilesControlChange);
			}
			for (i = 0; i < objectsControls.length; i++){
				eventMap.mapListener(objectsControls[i], Event.CHANGE, objectsControlChange);
			}
			for (i = 0; i < otherControls.length; i++){
				eventMap.mapListener(otherControls[i], Event.CHANGE, enviorementControlChange);
			}
			
			v.listRooms.dataProvider = mr.roomsDataProvider;
			
			v.background.dataProvider = ml.imagesDataProvider;
			v.foreground.dataProvider = ml.imagesDataProvider;
			v.listObjects.dataProvider = ml.objectsDataProvider;
			v.listTiles.dataProvider = ml.tilesDataProvider;
			
			eventMap.mapListener(v.btnCreateRoom, MouseEvent.CLICK, btnCreateRoomPress);
			eventMap.mapListener(v.btnDeleteCurrentRoom, MouseEvent.CLICK, btnDeleteRoomPress);
			eventMap.mapListener(v.listRooms, FlexEvent.VALUE_COMMIT, listRoomsSelectionChange);
			eventMap.mapListener(v.listRooms, IndexChangeEvent.CHANGE, listRoomsSelectionChange);
			eventMap.mapListener(v, Event.RESIZE, resetViewPortLater);
			eventMap.mapListener(v.gridSize, Event.CHANGE, resetViewPortLater);
			eventMap.mapListener(v.cellXSize, Event.CHANGE, resetViewPortLater);
			eventMap.mapListener(v.cellYSize, Event.CHANGE, resetViewPortLater);
			eventMap.mapListener(v.showGrid, Event.CHANGE, resetViewPortLater);
			eventMap.mapListener(v.btnResetViewPort, MouseEvent.CLICK, resetViewPort);
			
			eventMap.mapListener(v.dragSurface, DragEvent.DRAG_OVER, dragOver);
			eventMap.mapListener(v.dragSurface, DragEvent.DRAG_ENTER, dragEnter);
			eventMap.mapListener(v.dragSurface, DragEvent.DRAG_DROP, dragDrop);
			
			eventMap.mapListener(v.cont, MouseEvent.MOUSE_DOWN, mapMouseDown);
			eventMap.mapListener(v.cont, MouseEvent.MOUSE_UP, mapMouseUp);
			eventMap.mapListener(v.cont, MouseEvent.CLICK, mapMouseClick);
			eventMap.mapListener(v.cont.stage, MouseEvent.MOUSE_MOVE, stageMouseMove);
			
			eventMap.mapListener(v.cont.stage, MouseEvent.MOUSE_MOVE, stageMouseMove);
			
			setTilesControlsEnabled(false);
			setObjectsControlsEnabled(false);
			
			
			eventMap.mapListener(ms.selectedObjects, CollectionEvent.COLLECTION_CHANGE, updateObjectsControls, CollectionEvent);
			eventMap.mapListener(ms.selectedTiles, CollectionEvent.COLLECTION_CHANGE, updateTilesControls, CollectionEvent);
			
			eventMap.mapListener(eventDispatcher, EventObjectsPropertyChanged.OBJECTS_PROPERTIES_CHANGED, updateObjectsControls, EventObjectsPropertyChanged);
			eventMap.mapListener(eventDispatcher, EventTilesPropertyChanged.TILES_PROPERTIES_CHANGED, updateTilesControls, EventTilesPropertyChanged);
			
			eventMap.mapListener(v.btnRemoveTiles, MouseEvent.CLICK, btnRemoveTiles);
			eventMap.mapListener(v.btnRemoveObjects, MouseEvent.CLICK, btnRemoveObjects);
			
			eventMap.mapListener(v.zoom, Event.CHANGE, zoomChange);
			eventMap.mapListener(v.zoom, FlexEvent.VALUE_COMMIT, zoomChange);
			listRoomsSelectionChange();
		}
		
		public function zoomChange(e:Event = null) : void {
			v.cont.scaleX = v.cont.scaleY = v.zoom.value;
		}
		
		public function btnRemoveTiles(e:Event = null) : void {
			dispatch(new EventRemoveRoomItems(EventRemoveRoomItems.REMOVE_ROOM_ITEMS, currentRoom, ms.selectedTiles.toArray()));
			dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, []));
		}
		public function btnRemoveObjects(e:Event = null) : void {
			dispatch(new EventRemoveRoomItems(EventRemoveRoomItems.REMOVE_ROOM_ITEMS, currentRoom, ms.selectedObjects.toArray()));
			dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, null, []));
		}
		
		private function updateTilesControls(e:Event = null) : void {
			setTilesControlsEnabled(ms.selectedTiles.length > 0);
			v.accordion.selectedChild = v.tilesControlsContainer;
			var i:uint;
			if (ms.selectedTiles.length > 0){
				v.listTiles.selectedItem =  (ms.selectedTiles[0] as IsoTile).libraryReference;
				for (i = 0; i < tilesControls.length; i++){
					Util.getPropertyToControl(ms.selectedTiles[0], tilesControls[i]);
				}
			}
		}
		private function updateObjectsControls(e:Event = null) : void {
			setObjectsControlsEnabled(ms.selectedObjects.length > 0);
			v.accordion.selectedChild = v.objectControlsContainer;
			var i:uint;
			if (ms.selectedObjects.length > 0){
				v.listObjects.selectedItem =  (ms.selectedObjects[0] as IsoObject).libraryReference;
				for (i = 0; i < objectsControls.length; i++) {
					Util.getPropertyToControl(ms.selectedObjects[0], objectsControls[i]);
				}
			}
		}
		
		private function roomControlChange(e:Event = null) : void {
			if (v.listRooms.selectedItem ){
				var c:UIComponent = e.target as UIComponent;
				dispatch(new EventSetRoomProperty(EventSetRoomProperty.CHANGE_PROPERTY, currentRoom, c.name, Util.getControlValue(c)));
				if (e.target == v.background && e.type == Event.CHANGE){
					setTimeout(setBackgroundProperties, 300);
				}
				if (e.target == v.foreground && e.type == Event.CHANGE){
					setTimeout(setForegroundProperties, 300);
				}
				//			if (e.target == v.perspectiveXAngle || e.target == v.perspectiveYAngle || e.target == v.perspectiveZAngle){
				//				dispatch(new EventCurrentPerspectiveChange(EventCurrentPerspectiveChange.ROOM_SELECTION_CHANGE, new IsoPerspective(v.perspectiveXAngle.value, v.perspectiveYAngle.value, v.perspectiveZAngle.value)));
				//			}
				if (e.target == v.listRooms){
					dispatch(new EventCurrentPerspectiveChange(EventCurrentPerspectiveChange.ROOM_SELECTION_CHANGE, new IsoPerspective(v.perspectiveXAngle.value, v.perspectiveYAngle.value, v.perspectiveZAngle.value)));
				}				
			}
		}
		
		private function setBackgroundProperties() : void {
			v.backgroundOffsetX.value = -currentRoom.background.width / 2;
			v.backgroundOffsetY.value = -currentRoom.background.height;
		}
		private function setForegroundProperties() : void {
			v.foregroundOffsetX.value = -currentRoom.foreground.width / 2;
			v.foregroundOffsetY.value = -currentRoom.foreground.height;
		}
		
		private function tilesControlChange(e:Event = null) : void {
			var c:UIComponent = e.target as UIComponent;
			dispatch(new EventSetTilesProperty(EventSetTilesProperty.TILES_PROPERTY_CHAGE, ms.selectedTiles.toArray(), c.name, Util.getControlValue(c)));
		}
		private function objectsControlChange(e:Event = null) : void {
			var c:UIComponent = e.target as UIComponent;
			dispatch(new EventSetObjectsProperty(EventSetObjectsProperty.OBJECTS_PROPERTY_CHAGE, ms.selectedObjects.toArray(), c.name, Util.getControlValue(c)));
		}
		private function enviorementControlChange(e:Event = null) : void {
			currentRoom.map.showAxis = v.showAxis.selected;
			currentRoom.background.visible = !v.hideBackground.selected;
			currentRoom.foreground.visible = !v.hideForeground.selected;
			currentRoom.map.drawGrid = v.showGrid.selected;
			var i:uint;
			for (i = 0; i < currentRoom.map.numChildren; i++){
				if (currentRoom.map.getChildAt(i) is IsoTile){
					currentRoom.map.getChildAt(i).visible = !v.hideTiles.selected;
				}else
					if (currentRoom.map.getChildAt(i) is IsoObjectBase){
						currentRoom.map.getChildAt(i).visible = !v.hideObjects.selected;
						(currentRoom.map.getChildAt(i) as IsoObjectBase).drawHeight = v.showObjectsHeight.selected;
					}
			}
		}
		private function btnCreateRoomPress(e : Event = null) : void {
			dispatch(new EventCreateNewRoom(EventCreateNewRoom.CREATE_NEW_ROOM));
		}
		
		private function btnDeleteRoomPress(e:MouseEvent) : void {
			Alert.show("Are you sure you want to delete selected rooms?","Delete Rooms", Alert.YES | Alert.NO, null, removeSelectedObjects);
		}
		private function removeSelectedObjects(e:CloseEvent) : void {
			if ((e.detail & Alert.YES) > 0){
				dispatch(new EventRemoveRooms(EventRemoveRooms.REMOVE_ROOM, v.listRooms.selectedItems));
			}
		}
		private function resetViewPortLater(e : Event = null) : void {
			setTimeout(resetViewPort, 50);
		}
		
		private function resetViewPort(e : Event = null) : void {
			v.zoom.value = 1;
			ValidateQue.validateAll();
			v.cont.validateNow();
			v.srcoller.horizontalScrollBar.value = v.srcoller.horizontalScrollBar.maximum / 2;
			v.srcoller.verticalScrollBar.value = v.srcoller.verticalScrollBar.maximum / 2;
			
		}
		private function listRoomsSelectionChange(e : Event = null) : void {
			currentRoom = v.listRooms.selectedItem as IsoRoom;
			
			//			dispatch(new EventCurrentPerspectiveChange(EventCurrentPerspectiveChange.ROOM_SELECTION_CHANGE, v.listRooms.selectedItem));
			dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [], []));
			
			v.cont.sprite = currentRoom;
			
			if (v.listRooms.selectedIndex > -1 && v.listRooms.selectedItems.length == 1){
				v.roomControls.enabled = true;	
				var i:uint;
				
				for (i = 0; i < roomControls.length; i++){
					Util.getPropertyToControl(currentRoom , roomControls[i]);
				}
				enviorementControlChange();
				resetViewPort();
			}else{
				v.roomControls.enabled = false;
			}
		}
		private function dragOver(e : DragEvent) : void {
			if (e.ctrlKey){
				var p:Point = new Point(e.localX, e.localY);
				p = v.dragSurface.localToGlobal(p);
				if (e.dragInitiator == v.listTiles){
					dispatch(new EventAddItemToRoom(EventAddItemToRoom.ADD_ITEM_TO_ROOM, currentRoom, v.listTiles.selectedItem, p));
				}
			}
			
		}
		private function dragEnter(e : DragEvent) : void {
			if (e.dragInitiator == v.listTiles || e.dragInitiator == v.listObjects){
				DragManager.acceptDragDrop(v.dragSurface);
			}
		}
		private function dragDrop(e : DragEvent) : void {
			var p:Point = new Point(e.localX, e.localY);
			p = v.dragSurface.localToGlobal(p);
			var item:LBase;
			if (e.dragInitiator == v.listTiles){
				item = v.listTiles.selectedItem;
			}else
				if (e.dragInitiator == v.listObjects){
					item = v.listObjects.selectedItem;
				}else{
					throw(new Error("Unknown item type!"));
				}
			dispatch(new EventAddItemToRoom(EventAddItemToRoom.ADD_ITEM_TO_ROOM, currentRoom, item, p));
		}
		
		
		private function mapMouseDown(e:MouseEvent) : void {
			if (e.target is IsoObject){
				objectMoved = false;
				startDragObject = e.target as IsoObject;
				dragPosition = new Point2D(e.stageX, e.stageY);
			}
		}
		private function mapMouseUp(e:MouseEvent) : void {
			startDragObject = null;
		}
		private function mapMouseClick(e:MouseEvent) : void {
			var i:uint;
			if (objectMoved){
				objectMoved = false;
				return;
			}
			
			if ((e.ctrlKey || e.shiftKey) == false){
				if (e.target is IsoObject){
					dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [], [e.target]));
				}else
					if (e.target is IsoTile){
						dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [e.target], []));
					}
			}else
				if ((e.ctrlKey== true) && (e.shiftKey == false)){
					if (e.target is IsoObject){
						if (ms.isObjectSelected(e.target as IsoObject) == true){
							dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [], null, null, null, null, [e.target]));
						}else{
							dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [], null, null, [e.target] ));
						}
					}else
						if (e.target is IsoTile){
							if (ms.isTileSelected(e.target as IsoTile) == true){
								dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, null, [], null, null, [e.target] ));
							}else{
								dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, null, [], [e.target]));
							}
						}
				}else
					if ((e.ctrlKey== false) && (e.shiftKey == true)){
						var minX:Number;
						var maxX:Number;
						var minY:Number;
						var maxY:Number;
						if (e.target is IsoObject){
							var objects:Array = [e.target];
							if (ms.selectedObjects.length > 0){
								var fo:IsoObject = ms.selectedObjects.getItemAt(0) as IsoObject;
								var lo:IsoObject = e.target as IsoObject;
								minX = Math.min(fo.position.x, lo.position.x);
								maxX = Math.max(fo.position.x, lo.position.x);
								minY = Math.min(fo.position.y, lo.position.y);
								maxY = Math.max(fo.position.y, lo.position.y);
								objects = [fo];
								for (i = 0; i < currentRoom.map.numChildren; i++){
									if (currentRoom.map.getChildAt(i) is IsoObject){
										var obj:IsoObject = currentRoom.map.getChildAt(i) as IsoObject;
										if  (obj != fo){
											if (minX <= obj.position.x && minY <= obj.position.y && maxX >= obj.position.x && maxY >= obj.position.y){
												objects.push(obj);
											}
										}
									}
								}
							}
							dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [], objects));
						}else
							if (e.target is IsoTile){
								var tiles:Array = [e.target];
								if (ms.selectedTiles.length > 0){
									var ft:IsoTile = ms.selectedTiles.getItemAt(0) as IsoTile;
									var lt:IsoTile = e.target as IsoTile;
									minX = Math.min(ft.position.x, lt.position.x);
									maxX = Math.max(ft.position.x, lt.position.x);
									minY = Math.min(ft.position.y, lt.position.y);
									maxY = Math.max(ft.position.y, lt.position.y);
									tiles = [ft];
									for (i = 0; i < currentRoom.map.numChildren; i++){
										if (currentRoom.map.getChildAt(i) is IsoTile){
											var tile:IsoTile = currentRoom.map.getChildAt(i) as IsoTile;
											if  (tile != ft){
												if (minX <= tile.position.x && minY <= tile.position.y && maxX >= tile.position.x && maxY >= tile.position.y){
													tiles.push(tile);
												}
											}
										}
									}
								}
								dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, tiles, []));
							}
					}
		}
		private function stageMouseMove(e:MouseEvent) : void {
			if (startDragObject != null){
				objectMoved = true;
				if (ms.isObjectSelected(startDragObject) == false){
					if (e.ctrlKey){
						dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [], null, null, [startDragObject]));
					}else{
						dispatch(new EventSetSelection(EventSetSelection.SET_SELECTION, [], [startDragObject]));
					}
				}
				var delta:Point2D = dragPosition.clone();
				delta.x = e.stageX - delta.x;
				delta.x = delta.x / v.zoom.value;
				delta.y = e.stageY - delta.y;
				delta.y = delta.y / v.zoom.value;
				var p3d:Point3D = currentRoom.map.perspective.get3DCoordinates(delta);
				dragPosition = new Point2D(e.stageX, e.stageY);
				
				
				var i:uint;
				for (i = 0; i < ms.selectedObjects.length; i++) {
					var obj:IsoObject = ms.selectedObjects[i];
					dispatch(new EventSetObjectsProperty(EventSetObjectsProperty.OBJECTS_PROPERTY_CHAGE, [obj.position], "x", obj.position.x + p3d.x));
					dispatch(new EventSetObjectsProperty(EventSetObjectsProperty.OBJECTS_PROPERTY_CHAGE, [obj.position], "y", obj.position.y + p3d.y));
					dispatch(new EventSetObjectsProperty(EventSetObjectsProperty.OBJECTS_PROPERTY_CHAGE, [obj.position], "z", obj.position.z + p3d.z));
				}
			}
			
		}
		private function setTilesControlsEnabled(value:Boolean) : void {
			var i:uint;
			for (i = 0; i < tilesControls.length; i++){
				tilesControls[i].enabled = value;
			}
			v.btnRemoveTiles.enabled = value;
		}
		private function setObjectsControlsEnabled(value:Boolean) : void {
			var i:uint;
			for (i = 0; i < objectsControls.length; i++){
				objectsControls[i].enabled = value;
			}
			v.btnRemoveObjects.enabled = value;
		}
	}
}